﻿// -----------------------------------------------------------------------
// <copyright file="BaseTask.cs" company="">
// TODO: Update copyright text.
// </copyright>
// -----------------------------------------------------------------------

namespace Dhgms.TplHelper.Model.TaskHelper
{
    using System;
    using System.Diagnostics;
    using System.Threading.Tasks;

    using Dhgms.TplHelper.Model.Info;

    using NLog;

    /// <summary>
    /// Base class for a task
    /// </summary>
    /// <typeparam name="TTaskResultClass">
    /// The type of result being returned by the task
    /// </typeparam>
    public abstract class BaseTaskHelper<TTaskResultClass> : NonGenericBaseTaskHelper
        where TTaskResultClass : TaskResultBase, new()
    {
        /// <summary>
        /// The single instance of the task
        /// </summary>
        private readonly Lazy<System.Threading.Tasks.Task<TTaskResultClass>> taskInstance;

        /// <summary>
        /// Initializes a new instance of the <see cref="BaseTaskHelper{TTaskResultClass}"/> class. 
        /// </summary>
        /// <param name="name">
        /// The task Name.
        /// </param>
        protected BaseTaskHelper(string name)
        {
            if (string.IsNullOrWhiteSpace(name))
            {
                throw new ArgumentNullException("name");
            }

            this.Name = name;
            this.taskInstance = new Lazy<System.Threading.Tasks.Task<TTaskResultClass>>(() => new Task<TTaskResultClass>(this.Execute));
        }

        /// <summary>
        /// Gets the name of the current task
        /// </summary>
        protected string Name { get; private set; }

        /// <summary>
        /// Gets the TPL Task
        /// </summary>
        public System.Threading.Tasks.Task<TTaskResultClass> Task
        {
            get
            {
                return this.taskInstance.Value;
            }
        }

        /// <summary>Entry point for doing the donkey work.</summary>
        /// <returns>The Execution Result.</returns>
        internal abstract TTaskResultClass Execute();

        /// <summary>
        /// Runs a task instantly
        /// </summary>
        /// <returns>
        /// Job Result Information
        /// </returns>
        public TTaskResultClass RunSynchronously()
        {
            if (Debugger.IsAttached)
            {
                return this.Execute();
            }

            var t = this.Task;
            t.RunSynchronously();

            if (!t.IsFaulted)
            {
                return t.Result;
            }

            if (t.Exception == null)
            {
                throw new TaskCanceledException();
            }

            if (t.Exception.InnerExceptions != null && t.Exception.InnerExceptions.Count == 1)
            {
                throw t.Exception.InnerExceptions[0];
            }

            throw t.Exception;
        }
    }
}
